﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox;

namespace AVGDialogs
{
    internal partial class AVGDialogWindow : Form
    {

        private AVGDialog manager;

        Dictionary<string, int> labelMap = new Dictionary<string, int>();

        public AVGDialogWindow(AVGDialog manager)
        {
            InitializeComponent();
            this.manager = manager;
            FormClosed += AVGDialogWindow_FormClosed;
        }

        private void AVGDialogWindow_FormClosed(object sender, FormClosedEventArgs e)
        {
            attachForm.SizeChanged -= Container_SizeChanged;
            attachForm.Move -= Container_SizeChanged;
        }

        public int defaultTextSpeed = 48;
        List<AVGDialog.AVGEvent> events = new List<AVGDialog.AVGEvent>();

        private Form attachForm;

        public DialogResult ShowImpl(Form container)
        {
            attachForm = container;
            coverContainerWindow(container);
            SetControlPos(0.5, 0.9); 
            SetControlPos2();
            this.events.AddRange(manager.avgEvents);
            scanLabels();
            manager.Clear();
            return ShowDialog(container);
            
        }

        private void scanLabels()
        {
            for (int i = 0; i < events.Count; i++)
            {
                if (events[i] is AVGDialog.AVGLabelEvent label)
                {
                    labelMap.Add(label.labelName.Trim(), i);
                }
            }
        }

        private void Container_FormClosed(object sender, FormClosedEventArgs e)
        {
            Close();
        }

        private double windowX = 0.5, windowY = 0.9;

        private void Container_SizeChanged(object sender, EventArgs e)
        {
            coverContainerWindow(attachForm); 
            SetControlPos(windowX, windowY);
            SetControlPos2();
        }

        private void coverContainerWindow(Form container)
        {
            this.Size = container.Size;
            this.Location = container.Location;
            var containerTop = container.PointToScreen(Point.Empty);
            var padTop = containerTop.Y - container.Top;
            var padOther = (container.Width - container.ClientSize.Width) / 2;
            this.Padding = new Padding(padOther, padTop, padOther, padOther);
        }

        private void SetControlPos(double x,double y)
        {

            var parentClientSize = panWindowContent.Size;

            // 计算控件的新位置（百分比）
            int newX = (int)((parentClientSize.Width - panelAVGMain.Width) * x);
            int newY = (int)((parentClientSize.Height - panelAVGMain.Height) * y);

            // 设置控件的位置
            panelAVGMain.Location = new Point(newX, newY);
        }

        private void SetControlPos2()
        {
            panelSelection.Left = panWindowContent.Width / 2 - panelSelection.Width / 2;
            //                                                                * 0.9 (文字框默认的位置，确保选项框居中)
            panelSelection.Top = ((panWindowContent.Height - panelAVGMain.Height ) * 9 / 10) / 2 - panelSelection.Height / 2;
        }

        private void AVGDialog_Load(object sender, EventArgs e)
        {
            attachForm.SizeChanged += Container_SizeChanged;
            attachForm.Move += Container_SizeChanged;
            attachForm.FormClosed += Container_FormClosed;
            panelAVGMain.Visible = false;
            panelSelection.Visible = false; 
            if (selectionButtons == null) { selectionButtons = new Button[] { btnSelection1, btnSelection2, btnSelection3, btnSelection4, btnSelection5 }; }
            beginMainLoop();
        }

        public string currentSpeaker = "";
        public bool isShowingSpeaker
        {
            get { return lblAVGSpeaker.Visible; }
            set { lblAVGSpeaker.Visible = value; }
        }

        public int currentPointer = 0;


        public void beginMainLoop()
        {
            int nonInteractiveInstructionCount = 0;
            while (currentPointer < events.Count) { 
                var one = events[currentPointer];
                if (one is AVGDialog.AVGShowSelectionEvent ev2)
                {
                    disableSkip();
                    showSelection(ev2);
                    break;// Pause script for outer process
                }
                if (one is AVGDialog.AVGShowStringEvent ev3)
                {
                    typingString = "";
                    typedString = ev3.Message;
                    startTyping();
                    if(currentPointer < events.Count - 1)
                    {
                        if (events[currentPointer + 1] is AVGDialog.AVGShowSelectionEvent)
                        {
                            disableSkip();
                        }
                    }
                    break;// Pause script for outer process
                }
                
                if(one is AVGDialog.AVGDelayEvent evDelay)
                {
                    int ms = evDelay.delayMs;
                    currentPointer++;
                    btnSkip.Enabled = false;
                    tmrDelayable.Interval = ms;
                    tmrDelayable.Enabled = true;

                    break;
                }

                if(one is AVGDialog.AVGLabelEvent)
                {
                    currentPointer++;
                }

                if (one is AVGDialog.AVGExec exec)
                {
                    exec.exec();
                    currentPointer++;
                }

                if(one is AVGDialog.AVGGotoEvent gotoEvent)
                {
                    currentPointer = labelMap[gotoEvent.targetLabel];

                }

                if (one is AVGDialog.AVGGotoIfEvent gotoEvent2)
                {
                    currentPointer = gotoEvent2.predicate() ? labelMap[gotoEvent2.targetLabel] : currentPointer + 1;
                    
                }

                if (one is AVGDialog.AVGHideMessageBox)
                {
                    panelAVGMain.Visible = false;
                    panelSelection.Visible = false;
                    currentPointer++;
                }

                if(!(one is AVGDialog.ISkipableEvent))
                {
                    disableSkip();
                }

                if (one is AVGDialog.AVGClearSpeakerEvent)
                {
                    isShowingSpeaker = false;
                    currentPointer++;
                }
                if(one is AVGDialog.AVGMoveDialogPositionEvent ev)
                {
                    currentPointer++;
                    windowX = ev.X; windowY = ev.Y;
                    SetControlPos(windowX, windowY);
                }
                if(one is AVGDialog.AVGSetSpeakerEvent ev1)
                {
                    lblAVGSpeaker.Visible = true;
                    lblAVGSpeaker.Text = ev1.SpeakerName;
                    currentPointer++;
                }
                if(one is AVGDialog.AVGBeginSkipSection ev4)
                {
                    enableSkip(ev4.StorySummary);
                    currentPointer++;
                }
                if(one is AVGDialog.AVGEndSkipSection)
                {
                    disableSkip();
                    currentPointer++;
                }
                if (one is AVGDialog.AVGSetTextSize textSize)
                {
                    setTextSize(textSize.size);
                    currentPointer++;
                }

                if (one is AVGDialog.AVGSetSpeakerColor speakerColor)
                {
                    lblAVGSpeaker.ForeColor = speakerColor.color;
                    currentPointer++;
                }
                if (one is AVGDialog.AVGSetTextColor textColor)
                {
                    lblAvgText.ForeColor = textColor.color;
                    currentPointer++;
                }

                if(one is AVGDialog.AVGStrikeScreen strikeScreen)
                {
                    strikeWindow(strikeScreen.mode, strikeScreen.times, strikeScreen.amplitude);
                    currentPointer++;
                }
                if(one is AVGDialog.AVGSetSelectionColor selectionColor)
                {
                    selectionButtons[selectionColor.which - 1].ForeColor = selectionColor.color;
                    currentPointer++;
                }
                
                nonInteractiveInstructionCount++;
                if(nonInteractiveInstructionCount > 2048)
                {
                    throw new TimeoutException("非交互指令超过了最大限制");
                }


            }
            if (currentPointer >= events.Count) {
                // All events are processed. 
                DialogResult = DialogResult.OK;
                Close();
            }
        }

        private void tmrDelayable_Tick(object sender, EventArgs e)
        {
            tmrDelayable.Enabled = false;
            btnSkip.Enabled = true;
            BeginInvoke(new Action(() =>
            {

                beginMainLoop();
            }));
        }
        public void evalSkip(AVGDialog.AVGEvent one)
        {

            if (one is AVGDialog.AVGClearSpeakerEvent)
            {
                isShowingSpeaker = false;
            }
            if (one is AVGDialog.AVGMoveDialogPositionEvent ev)
            {
                windowX = ev.X; windowY = ev.Y;
                SetControlPos(windowX, windowY);
            }
            if (one is AVGDialog.AVGSetSpeakerEvent ev1)
            {
                lblAVGSpeaker.Visible = true;
                lblAVGSpeaker.Text = ev1.SpeakerName;
            }
            if (one is AVGDialog.AVGBeginSkipSection ev4)
            {
                enableSkip(ev4.StorySummary);
            }
            if (one is AVGDialog.AVGEndSkipSection)
            {
                disableSkip();
            }
            if(one is AVGDialog.AVGSetTextSize textSize)
            {
                setTextSize(textSize.size);
            }
            if (one is AVGDialog.AVGSetSpeakerColor speakerColor)
            {
                lblAVGSpeaker.ForeColor = speakerColor.color;
            }
            if (one is AVGDialog.AVGSetTextColor textColor)
            {
                lblAvgText.ForeColor = textColor.color;
            }
            if (one is AVGDialog.AVGSetSelectionColor selectionColor)
            {
                selectionButtons[selectionColor.which - 1].ForeColor = selectionColor.color;
            }
        }

        public string typingString = "";
        public string typedString = "";

        bool inStringMessage = true;


        private void setTextSize(AVGDialog.AVGTextSizes size)
        {
            defaultTextSpeed = 48;
            if(size == AVGDialog.AVGTextSizes.Small)
            {
                lblAvgText.Font = lblSmallFont.Font;
            }
            if (size == AVGDialog.AVGTextSizes.Normal)
            {
                lblAvgText.Font = lblNormalFont.Font;
            }
            if (size == AVGDialog.AVGTextSizes.Large)
            {
                defaultTextSpeed = 80;
                lblAvgText.Font = lblLargeFont.Font;
            }
        }

        public void startTyping()
        {
            panelAVGMain.Visible = true;
            tmrPrintString.Enabled = true;
            inStringMessage = true;
            lblAvgText.Text = typingString;
            imgNextIndicator.Visible = false;

        }


        private void tmrPrintString_Tick(object sender, EventArgs e)
        {
            if(tmrPrintString.Interval != defaultTextSpeed)
            {

                tmrPrintString.Interval = defaultTextSpeed;
            }
            if (typingString.Length < typedString.Length) {
                var typingChar = typedString[typingString.Length].ToString();
                typingString += typingChar;
                if ("，。？！,?!;；:：".Contains(typingChar))
                {
                    tmrPrintString.Interval = 180;
                }
            }
            else
            {
                tmrPrintString.Enabled = false;
                imgNextIndicator.Visible = true;
                if (isShowingSpeaker)
                {
                    manager.PushBacklog("[" + lblAVGSpeaker.Text + "] " + typedString);
                }
                else
                {

                    manager.PushBacklog(typedString);
                }
            }
            lblAvgText.Text = typingString;

        }

        private void lblAvgText_MouseUp(object sender, MouseEventArgs e)
        {
            if (ignoreFirstTouch)
            {
                ignoreFirstTouch = false;
                return;
            }


            if (inStringMessage)
            {
                if (tmrPrintString.Enabled)
                {
                    typingString = typedString;
                }
                else
                {
                    currentPointer++;
                    inStringMessage = false;
                    imgNextIndicator.Visible = false;
                    beginMainLoop();
                }
            }

        }

        Button[] selectionButtons = null;

        public void showSelection(AVGDialog.AVGShowSelectionEvent it)
        {
            
            SetControlPos2();
            imgNextIndicator.Visible = false;
            panelSelection.SuspendLayout();
            for (int i = 0; i < selectionButtons.Length; i++)
            {
                selectionButtons[i].Visible = i < it.Selections.Count;
                if (i < it.Selections.Count) {
                    selectionButtons[i].Text = it.Selections[i];
                    selectionButtons[i].Tag = i + 1;
                }
            }
            // 重新排列按钮的位置
            void setButtonPos(int i,double d)
            {
                selectionButtons[i].Width = panelSelection.Width;
                selectionButtons[i].Left = 0;
                selectionButtons[i].Top = (int)(d * (panelSelection.Height - selectionButtons[i].Height));
            }
            var beginY = 0.5 - (it.Selections.Count - 1) * 0.25d / 2d;
            for (int i = 0; i < it.Selections.Count; i++)
            {
                double p = (double)i * 0.25d;
                setButtonPos(i, p + beginY);
            }


            panelSelection.ResumeLayout();
            panelSelection.Visible = true;
        }
        private void btnSelectionClick(object sender, EventArgs e)
        {
            manager.lastSelection = int.Parse(((Button)sender).Tag.ToString());
            manager.PushBacklog("<选择> "+((Button)sender).Text);
            panelSelection.Visible = false; 
            foreach (var item in selectionButtons)
            {
                item.ForeColor = Color.White;
            }
            currentPointer++;
            beginMainLoop();
        }



        private bool isDragging = false;
        private Point dragStartPoint;




        private void AVGDialogWindow_MouseDown(object sender, MouseEventArgs e)
        {
            // 仅在左键按下时启动拖动
            if (e.Button == MouseButtons.Left)
            {
                isDragging = true;
                dragStartPoint = new Point(e.X, e.Y); // 记录鼠标按下的位置
            }
        }

        private void AVGDialogWindow_MouseUp(object sender, MouseEventArgs e)
        {
            // 左键释放时停止拖动
            if (e.Button == MouseButtons.Left)
            {
                isDragging = false;
            }
        }

        private void btnBackLog_Click(object sender, EventArgs e)
        {
            Form backlogForm = new Form();
            backlogForm.ShowInTaskbar = false;
            backlogForm.Width = panWindowContent.Width;
            backlogForm.Height = panWindowContent.Height;
            backlogForm.Text = "对话记录";
            backlogForm.StartPosition = FormStartPosition.Manual;
            backlogForm.Location = this.PointToScreen(panWindowContent.Location);
            backlogForm.BackColor = panelAVGMain.BackColor;
            backlogForm.ForeColor = lblAvgText.ForeColor;
            backlogForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            TextBox tb = new TextBox();
            tb.ReadOnly = true;
            tb.BackColor = backlogForm.BackColor;
            tb.ForeColor = backlogForm.ForeColor;
            tb.Font = lblAvgText.Font;
            tb.Multiline = true;
            tb.ScrollBars = ScrollBars.Vertical;
            tb.Text = string.Join("\r\n\r\n", manager.backlog);
            backlogForm.Controls.Add(tb);
            tb.Dock = DockStyle.Fill;
            backlogForm.Shown += delegate
            {

                tb.SelectionStart = tb.TextLength;
                tb.ScrollToCaret();
            };
            backlogForm.ShowDialog(this);

            
        }
        bool ignoreFirstTouch = false;
        private void AVGDialogWindow_Deactivate(object sender, EventArgs e)
        {
            ignoreFirstTouch = true;
        }



        private string storySummary = "";

        private void enableSkip(string summary)
        {
            btnSkip.Visible = true;
            storySummary = summary;
        }

        private void disableSkip()
        {
            btnSkip.Visible = false;
            storySummary = "";
        }

        private void btnSkip_Click(object sender, EventArgs e)
        {
            FrmSkipDialog dlg = new FrmSkipDialog();
            dlg.lblStorySummary.Text = "剧情梗概：\r\n"+(string.IsNullOrWhiteSpace(storySummary) ? "无" : storySummary);
            if(dlg.ShowDialog(this) == DialogResult.OK)
            {
                int skipTarget = -1;
                for (int i = currentPointer; i < events.Count; i++)
                {
                    if(i < events.Count - 1)
                    {
                        if (events[i+1] is AVGDialog.AVGShowSelectionEvent)
                        {
                            skipTarget = i;
                            break;
                        }
                    }
                    if (events[i] is AVGDialog.AVGEndSkipSection )
                    {
                        skipTarget = i+1;
                        break;
                    }
                    if (!(events[i] is  AVGDialog.ISkipableEvent))
                    {
                        skipTarget = i;
                        break;
                    }
                }
                manager.PushBacklog("<跳过剧情> " + storySummary);
                if (skipTarget == -1)
                {
                    tmrPrintString.Enabled = false;
                    DialogResult = DialogResult.OK;
                    Close();
                }
                else
                {
                    for (var i = currentPointer;  i < skipTarget;  i++)
                    {
                        var skippedItem = events[i];

                        evalSkip(skippedItem);

                    }

                    currentPointer = skipTarget;
                    tmrPrintString.Enabled = false;
                    inStringMessage = false;
                    panelAVGMain.Visible = false;
                    panelSelection.Visible = false;
                    beginMainLoop();
                }
            }

        }

        private void AVGDialogWindow_MouseMove(object sender, MouseEventArgs e)
        {
            // 如果正在拖动，则移动窗口
            if (isDragging)
            {
                // 计算新位置（当前鼠标位置 - 按下时的偏移）
                Point newLocation = attachForm.Location;
                newLocation.X += e.X - dragStartPoint.X;
                newLocation.Y += e.Y - dragStartPoint.Y;

                // 设置窗口的新位置
                attachForm.Location = newLocation;
            }
        }

        Random random = new Random();
        int[] GenerateStrikingSequence(int count, int amplitude, bool signIsRandom = false,bool enabled = true)
        {
            // 检查输入参数
            if (count < 1 || amplitude <= 0)
            {
                throw new ArgumentException("Invalid input: count must be at least 1 and amplitude must be positive.");
            }

            // 初始化数组
            int[] sequence = new int[count * 2 + 1];
            if (!enabled)
            {
                return sequence;
            }
            // 填充数组
            for (int i = 0; i < sequence.Length; i++)
            {
                // 计算基础值
                int baseValue = amplitude - (amplitude / count) * (i / 2);
                // 添加随机性
                int randomRange = (int)(baseValue * 0.2);
                int randomOffset = random.Next(-randomRange, randomRange + 1);
                // 应用正负交替
                int sign;
                if (signIsRandom)
                {
                    sign = random.Next(0, 2) == 0 ? 1 : -1;
                }
                else
                {
                    sign = (i % 2 == 0) ? 1 : -1;
                }
                sequence[i] = sign * (baseValue + randomOffset);
            }

            // 确保最后一个值为0
            sequence[sequence.Length - 1] = 0;

            return sequence;
        }

        int[] strikingX = null;
        int[] strikingY = null;
        Point beginStrikingPoint;
        int strikingProgress = 0;
        Form strikingTarget = null;


        void strikeWindow(AVGDialog.AVGStrikeScreenMode mode,int count,int amplitude)
        {
            if (attachForm.WindowState == FormWindowState.Maximized) {
                strikingTarget = this;
            }
            else
            {
                strikingTarget = attachForm;
            }

            if (tmrScreenStriking.Enabled)
            {
                strikingProgress = 0;
            }
            else
            {
                strikingProgress = 0;
                beginStrikingPoint = strikingTarget.Location;
            }

            bool horizental = mode == AVGDialog.AVGStrikeScreenMode.Horizontal || mode == AVGDialog.AVGStrikeScreenMode.Both;
            bool vertical = mode == AVGDialog.AVGStrikeScreenMode.Vertical || mode == AVGDialog.AVGStrikeScreenMode.Both;
            bool randomSign = mode == AVGDialog.AVGStrikeScreenMode.Both;
            strikingX = GenerateStrikingSequence(count, amplitude,randomSign,horizental);
            strikingY = GenerateStrikingSequence(count, amplitude,randomSign,vertical);

            tmrScreenStriking.Enabled = true;
        }


        private void tmrScreenStriking_Tick(object sender, EventArgs e)
        {

            strikingTarget.Location = new Point(beginStrikingPoint.X + strikingX[strikingProgress],beginStrikingPoint.Y +  strikingY[strikingProgress]);
            strikingProgress++;
            if (strikingProgress >= strikingX.Length) {
                tmrScreenStriking.Enabled = false;
                return;
            }
        }
    }
}
